#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"

#include "BList.h"

#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"

#include "SpecialTerm.h"



Sort::Sort()
{
	m_defined=true;

	m_name=0;
	m_super=0;
	m_ontology=0;

	m_data_type=-1;

	m_seed=0;

} /* Sort::Sort */ 


Sort::Sort(Symbol *name,Sort *super,Ontology *o)
{
	m_defined=true;

	m_name=new Symbol(name);
	m_super=super;
	if (m_super!=0) {
		m_super->m_subsorts.Add(this);
//		printf("Adding %s to %s\n",name->get(),m_super->get());
	} // if
	m_ontology=o;

	m_data_type=-1;
	if (m_super!=0) m_data_type=m_super->m_data_type;

	m_seed=0;
} /* Sort::Sort */ 


Sort::Sort(char *name,char *super,Ontology *o)
{
	m_defined=true;

	m_name=new Symbol(name);
	m_super=o->get_sort(super);
	if (m_super!=0) {
		m_super->m_subsorts.Add(this);
//		printf("Adding %s to %s\n",name,m_super->get());
	} // if
	m_ontology=o;

	m_data_type=-1;
	if (m_super!=0) m_data_type=m_super->m_data_type;

	m_seed=0;
} /* Sort::Sort */ 


Sort::~Sort()
{
	Sort *s;

	delete m_name;
	if (m_super!=0) m_super->m_subsorts.DeleteElement(this);

	while(!m_subsorts.EmptyP()) {
		s=m_subsorts.ExtractIni();
		s->m_super=m_super;
	} /* while */ 

	m_feature_names.Delete();
	while(!m_feature_sorts.EmptyP()) m_feature_sorts.ExtractIni();

	m_super=0;
	m_ontology=0;

	if (m_seed!=0) delete m_seed;
	m_seed=0;
} /* Sort::~Sort */ 


char *Sort::get(void)
{
	if (m_name!=0) return m_name->get();
	return 0;
} /* Sort::get */ 


int Sort::get_data_type(void)
{
	return m_data_type;
} /* Sort::get_data_type */ 


Ontology *Sort::getOntology(void)
{
	return m_ontology;
} /* Sort::getOntology */ 



bool Sort::inSort(int i)
{
	if (m_data_type==-1) return true;
	if (m_data_type==0) return true;
	return false;
} /* Sort::inSort */ 


bool Sort::inSort(float f)
{
	if (m_data_type==-1) return true;
	if (m_data_type==0) return true;
	return false;
} /* Sort::inSort */ 


bool Sort::inSort(Symbol *s)
{	
	if (m_data_type==-1) return true;
	if (m_data_type==2) return true;
	return false;
} /* Sort:inSort */ 


bool Sort::inSort(FeatureTerm *f)
{
	Sort *s;

	s=f->getSort();
	if (s==0) return true;
	if (s==this) return true;

	while(s->m_super!=0) {
		s=s->m_super;
		if (s==this) return true;
	} /* while */ 
	return false;
} /* Sort::inSort */ 


FeatureTerm *Sort::random(void)
{
	switch(m_data_type) {
	case DATATYPE_ABSTRACT:
			{
				Sort *s=m_ontology->get_random_sort();
				if (s!=0) return s->random();
				return 0;
			}
			break;
	case DATATYPE_INTEGER: return new FeatureTerm((char *)0,int(rand()),m_ontology);
			break;
	case DATATYPE_FLOAT: return new FeatureTerm((char *)0, (float(rand())/float(RAND_MAX))*float(rand()) , m_ontology);
			break;
	case DATATYPE_SYMBOL:
			{
				char tmp[256];
				int i;

				tmp[0]='a'+(rand()%26);

				for(i=1;i<255 && (rand()%16)!=0;i++) {
					tmp[i]='a'+(rand()%26);
				} /* for */ 
				tmp[i]=0;
				return new FeatureTerm((Symbol *)0,new Symbol(tmp),m_ontology);
			}

			break;
	case DATATYPE_FEATURETERM: /* Generate a random Feature Term: */ 
			{
				FeatureTerm *f,*value;
				Sort *s;
				bool selected=false;
				List<Symbol> fnl;
				Symbol *fn;
				List<Sort> fsl;
				Sort *fs;

				/* randomly choose the sort: */ 
				s=this;
				while(s->m_super!=0 && !selected) {
					if ((rand()%4)!=0) selected=true;
								  else s=s->m_super;
				} /* while */ 

				f=new FeatureTerm((Symbol *)0,s,0);

				/* Randomly fill the features: */ 
				{
					while(s!=0) {
						fnl=s->m_feature_names;
						fsl=s->m_feature_sorts;
						fnl.Rewind();
						fsl.Rewind();
						while(fnl.Iterate(fn) && fsl.Iterate(fs)) {
							if ((rand()%2)==0) {
								value=fs->random();
								f->defineFeatureValue(fn,value);
								delete value;
							} /* if */ 
						} /* while */ 
						s=s->m_super;
					} /* while */ 
				}
				return f;
			}
						
			return 0;
			break;
	case DATATYPE_SPECIAL:
			m_seed->random();
			break;
	} /* if */ 

	return 0;
} /* Sort::random */ 


bool Sort::operator==(Sort &s)
{
	if (&s==this) return true;
	return false;
} /* Sort::operator== */ 


bool Sort::save(FILE *fp)
{
	List<Symbol> l;
	Symbol *s;
	List<Sort> l2;
	Sort *s2;
	List<bool> l3;

	m_name->save(fp);
	if (m_super!=0) m_super->m_name->save(fp);
			   else fprintf(fp,"NULLSYM\n");

	fprintf(fp,"%i\n",m_data_type);

	fprintf(fp,"%i\n",m_feature_names.Length());
	l.Instance(m_feature_names);
	l.Rewind();
	while (l.Iterate(s)) s->save(fp);

	fprintf(fp,"%i\n",m_feature_sorts.Length());
	l2.Instance(m_feature_sorts);
	l2.Rewind();
	while (l2.Iterate(s2)) s2->m_name->save(fp);

	return true;
} /* Sort::save */ 


bool Sort::hasFeature(Symbol *name)
{
	return featureSort(name)!=0;
} /* Sort::hasFeature */ 


bool Sort::hasFeature(char *name)
{
	return featureSort(name)!=0;
} /* Sort::hasFeature */ 


Sort *Sort::featureSort(Symbol *name)
{
	int pos=-1;

	pos=m_feature_names.Position(name);
	if (pos!=-1) {
		return m_feature_sorts[pos];
	} else {
		if (m_super!=0) return m_super->featureSort(name);
		return 0;
	} /* if */ 
} /* Sort::featureSort */ 


Sort *Sort::featureSort(char *name)
{
	Sort *s;
	Symbol *sym=new Symbol(name);

	s=featureSort(sym);
	delete sym;

	return s;
} /* Sort::featureSort */ 


FeatureTerm *Sort::featureDefaultValue(Symbol *name)
{
	int pos=-1;

	pos=m_feature_names.Position(name);
	if (pos!=-1) {
		return m_feature_default[pos];
	} else {
		if (m_super!=0) return m_super->featureDefaultValue(name);
		return 0;
	} /* if */ 
} /* Sort::featureDefaultValue */ 


FeatureTerm *Sort::featureDefaultValue(char *name)
{
	FeatureTerm *dv;
	Symbol *sym=new Symbol(name);

	dv=featureDefaultValue(sym);
	delete sym;

	return dv;
} /* Sort::featureDefaultValue */ 


bool Sort::featureSingleton(Symbol *name)
{
	int pos=-1;

	pos=m_feature_names.Position(name);
	if (pos!=-1) {
		return *(m_feature_singleton[pos]);
	} else {
		if (m_super!=0) return m_super->featureSingleton(name);
		return false;
	} /* if */ 
} /* Sort::featureSingleton */ 


bool Sort::featureSingleton(char *name)
{
	bool dv;
	Symbol *sym=new Symbol(name);

	dv=featureSingleton(sym);
	delete sym;

	return dv;
} /* Sort::featureSingleton */ 


Sort *Sort::Antiunification(Sort *s)
{
	Sort *au=this;

	while(au!=0) {
		if (au->isSubsort(s)) return au;
		au=au->m_super;
	} /* while */ 
	return 0;
} /* Sort::Antiunification */ 


Sort *Sort::Unification(Sort *s)
{
	if (this->isSubsort(s)) return s;
	if (s->isSubsort(this)) return this;

	return 0;
} /* Sort::Unification */ 



bool Sort::isSubsort(Sort *s)
{
	List<Sort> l;
	Sort *s2;

	if (s==this) return true;

	l.Instance(m_subsorts);
	l.Rewind();
	while(l.Iterate(s2)) {
		if (s2->isSubsort(s)) return true;
	} /* while */ 

	return false;
} /* Sort::isSubsort */ 


bool Sort::is_a(Sort *s)
{
	List<Sort> l;
	Sort *s2;

	if (s==this) return true;

	l.Instance(s->m_subsorts);
	l.Rewind();
	while(l.Iterate(s2)) {
		if (is_a(s2)) return true;
	} /* while */ 

	return false;
} /* Sort::is_a */ 


// returns the distance in the sort hierarchy (only if this is a subsort of s)
int Sort::refinementSteps(Sort *s)
{
	int tmp;
	List<Sort> l;
	Sort *s2;

	if (s==this) return 0;

	l.Instance(m_subsorts);
	l.Rewind();
	while(l.Iterate(s2)) {
		tmp=s2->refinementSteps(s);
		if (tmp>=0) return tmp+1;
	} /* while */ 

	return -1;
} /* Sort::isSubsort */ 


List<Sort> *Sort::getSubSorts(void)
{
	List<Sort> *l=new List<Sort>;

	l->Instance(m_subsorts);

	return l;
} /* Sort::getSubSorts */ 


void Sort::addFeature(Symbol *name,Sort *sort,FeatureTerm *defaultvalue,bool singleton)
{
	m_feature_names.Add(new Symbol(name));
	m_feature_sorts.Add(sort);
	m_feature_default.Add(defaultvalue);
	m_feature_singleton.Add(new bool(singleton));
} /* Sort::addFeature */ 


void Sort::addFeature(char *name,char *sort,FeatureTerm *defaultvalue,Ontology *o,bool singleton)
{
	m_feature_names.Add(new Symbol(name));
	m_feature_sorts.Add(o->get_sort(sort));
	m_feature_default.Add(defaultvalue);
	m_feature_singleton.Add(new bool(singleton));
} /* Sort::addFeature */ 


List<Symbol> *Sort::getFeatures(void)
{
	if (m_super==0) {
		List<Symbol> *l=new List<Symbol>;
		List<Symbol> sl;
		Symbol *fn;

		sl.Instance(m_feature_names);
		sl.Rewind();
		while(sl.Iterate(fn)) l->Add(new Symbol(fn));

		return l;
	} else {
		List<Symbol> *l=m_super->getFeatures();
		List<Symbol> sl;
		Symbol *fn;

		sl.Instance(m_feature_names);
		sl.Rewind();
		while(sl.Iterate(fn)) l->Add(new Symbol(fn));

		return l;
	} /* if */ 
} /* Sort::getFeatures */ 


Sort *Sort::getSuper(void)
{
	return m_super;
} /* Sort::getSuper */ 


SpecialTerm *Sort::createSpecial(List<Symbol> *names,List<FeatureTerm> *arguments)
{
	if (m_seed!=0) {
		return m_seed->newSpecialTerm(this,names,arguments);
	} // if 

	return 0;
} /* Sort::createSpecial */ 


void Sort::setSpecialSeed(SpecialTerm *seed)
{
	m_seed=seed;
} /* Sort::setSpecialSeed */ 


